package musictrackrecommendation;

import java.sql.SQLException;

import odnoklassniki.OdnoklassnikiDataset;
import lastfm.LastfmDataset;
import randomwalk.socialgraph.CompleteUsersTracksGraph;
import randomwalk.socialgraph.SocialGraph;
import randomwalk.socialgraph.UsersTracks;
import randomwalk.socialgraph.UsersTracksSimilarUsers;
import simpledataset.SimpleMatrix;
import evaluation.EvaluationMetric;
import evaluation.HalfLifeUtility;
import evaluation.RecallPrecision;
import evaluation.PrecisionN;

/**
 * @author  user
 */
public class ExperimentParameters {
	//Values for UserUserValueRetrievalMethod
	public static final int GET_AVERAGE_PLAYCOUNT = 1;
	public static final int GET_COSINE_SIMILARITY = 2;
	//Values for normalizationMethod
	public static final int WHOLE_COLUMN_NORMALIZATION = 1;
	public static final int SEPARATE_COLUMN_NORMALIZATION = 2;
	//Datasets
	public static final int SIMPLE_DATASET = 1;
	public static final int LASTFM_SMALL_DATASET = 2;
	public static final int ODNOKLASSNIKI_DATASET = 3;
	//Included relations
	public static final int USERS_TRACKS_FRIENDS = 1;
	public static final int USERS_TRACKS = 2;
	public static final int COMPLETE_USERS_TRACKS_GRAPH = 3;
	//Relevant Verification type
	public static final int PARTIAL_TRACK_REMOVAL = 1;
	public static final int QUIZ_SET = 2;
	
	
	private String title;
	private double restartProbability;
	private int UserUserValueRetrievalMethod;
	private int normalizationMethod;
	private int datasetType;
	private double userUserColumnNorm;
	private double trackUserColumnNorm;
	private double userTrackColumnNorm;
	private double trackTrackColumnNorm;
	private int includedRelations;
	private int [] users;
	private EvaluationMetric[] metrics;
	private int relevantVerificationType;
	
	private ExperimentParameters() { }

	/*
    * Singleton Holder
    */
    /**
	 * @author  user
	 */
    private static class ExperimentParametersHolder { 
    	public static final ExperimentParameters instance 
            = new ExperimentParameters();
    }

    public static ExperimentParameters getInstance() {
            return ExperimentParametersHolder.instance;
    }

    /**
	 * @return  the title
	 */
	public String getTitle() {
		return title;
	}

	/**
	 * @param title  the title to set
	 */
	public void setTitle(String title) {
		this.title = title;
	}
    
    
	/**
	 * @return  the restartProbability
	 */
	public double getRestartProbability() {
		return restartProbability;
	}

	/**
	 * @param restartProbability  the restartProbability to set
	 */
	public void setRestartProbability(double restartProbability) {
		this.restartProbability = restartProbability;
	}

	/**
	 * @return  the userUserValueRetrievalMethod
	 */
	public int getUserUserValueRetrievalMethod() {
		return UserUserValueRetrievalMethod;
	}

	/**
	 * @param userUserValueRetrievalMethod  the userUserValueRetrievalMethod to set
	 */
	public void setUserUserValueRetrievalMethod(
			int userUserValueRetrievalMethod) {
		UserUserValueRetrievalMethod = userUserValueRetrievalMethod;
	}
	

	
	/**
	 * @return  the normalizationMethod
	 */
	public int getNormalizationMethod() {
		return normalizationMethod;
	}

	/**
	 * @param normalizationMethod  the normalizationMethod to set
	 */
	public void setNormalizationMethod(int normalizationMethod) {
		this.normalizationMethod = normalizationMethod;
	}
	
	/**
	 * @param datasetType
	 */
	public void setDatasetType(int datasetType) {
		this.datasetType = datasetType;
	}

	/**
	 * @return
	 */
	public int getDatasetType() {
		return datasetType;
	}

	/**
	 * @return  the users
	 */
	public int [] getUsers() {
		return users;
	}

	/**
	 * @param users  the users to set
	 */
	public void setUsers(int [] users) {
		this.users = users;
	}

	/**
	 * @return  the metrics
	 */
	public EvaluationMetric[] getMetrics() {
		return metrics;
	}

	/**
	 * @param metrics  the metrics to set
	 */
	public void setMetrics(EvaluationMetric[] metrics) {
		this.metrics = metrics;
	}
	
	public Dataset getDatasetProperties() {
		switch(datasetType) {
		case SIMPLE_DATASET:
			return new SimpleMatrix();
		case LASTFM_SMALL_DATASET:
			return new LastfmDataset();
		case ODNOKLASSNIKI_DATASET:
			return new OdnoklassnikiDataset();
		default:
			return new SimpleMatrix();
		}
	}
	
	public DatabaseDataset getDatasetDatabase() {
		switch(datasetType) {
		case LASTFM_SMALL_DATASET:
			return new LastfmDataset();
		case ODNOKLASSNIKI_DATASET:
			return new OdnoklassnikiDataset();
		default:
			return null;
		}
	}
	
	public SocialGraph getSocialGraph() throws ClassNotFoundException, SQLException {
		switch(getIncludedRelations()) {
		case USERS_TRACKS_FRIENDS:
			return new UsersTracksSimilarUsers();
		case USERS_TRACKS:
			return new UsersTracks();
		case COMPLETE_USERS_TRACKS_GRAPH:
			return new CompleteUsersTracksGraph();
		default:
			return null;
		}
	}

	/**
	 * @param includedRelations  the includedRelations to set
	 */
	public void setIncludedRelations(int includedRelations) {
		this.includedRelations = includedRelations;
	}

	/**
	 * @return  the includedRelations
	 */
	public int getIncludedRelations() {
		return includedRelations;
	}
	
	public static void setOdnoklassnikiRecommendation(int usersCount) {
		
		ExperimentParameters parameters = ExperimentParameters.getInstance();
		
		parameters.setTitle("Improved Recommendation with musical similarity.");
		
		parameters.setIncludedRelations(ExperimentParameters.USERS_TRACKS);
		
		parameters.setDatasetType(ExperimentParameters.ODNOKLASSNIKI_DATASET);
		
		parameters.setRestartProbability(0.8);
		
		int normalizationMethod = ExperimentParameters.WHOLE_COLUMN_NORMALIZATION;
		
		parameters.setNormalizationMethod(normalizationMethod);
		
		int [] allUsers = parameters.getDatasetProperties().getUserList();
		int [] users = java.util.Arrays.copyOfRange(allUsers, 0, usersCount);
		
		parameters.setUsers(users);
		
		EvaluationMetric[] metrics = {
				new RecallPrecision(),
				new HalfLifeUtility(5)};
		
		parameters.setMetrics(metrics);
	}
	
	public static void setSimpleRecommendation() {
		
		ExperimentParameters parameters = ExperimentParameters.getInstance();
		
		parameters.setTitle("Simple Recommendation with 5 users and 15 tracks.");
		
		parameters.setDatasetType(ExperimentParameters.SIMPLE_DATASET);
		
		parameters.setIncludedRelations(ExperimentParameters.USERS_TRACKS_FRIENDS);
		
		parameters.setRestartProbability(0.8);
		
		int userMethod = ExperimentParameters.GET_AVERAGE_PLAYCOUNT;
		parameters.setUserUserValueRetrievalMethod(userMethod);
		
		int normalizationMethod = ExperimentParameters.SEPARATE_COLUMN_NORMALIZATION;
		double userNorm = 0.6;
		double trackNorm = 0.4;
		
		parameters.setNormalizationMethod(normalizationMethod);
		parameters.setUserUserColumnNorm(userNorm);
		parameters.setTrackUserColumnNorm(trackNorm);
		
		int [] allUsers = {2};
		
		parameters.setUsers(allUsers);
		
		EvaluationMetric[] metrics = {
				new RecallPrecision(),
				new HalfLifeUtility(5)};
		
		parameters.setMetrics(metrics);
	}
	
	public static void setBaselineRecommendation(int usersCount) {
		ExperimentParameters parameters = ExperimentParameters.getInstance();
		
		parameters.setTitle("Baseline Recommendation.");
		
		parameters.setDatasetType(ExperimentParameters.LASTFM_SMALL_DATASET);
		
		parameters.setIncludedRelations(ExperimentParameters.USERS_TRACKS_FRIENDS);
		
		parameters.setRestartProbability(0.8);
		
		int userMethod = ExperimentParameters.GET_AVERAGE_PLAYCOUNT;
		parameters.setUserUserValueRetrievalMethod(userMethod);
		
		int normalizationMethod = ExperimentParameters.SEPARATE_COLUMN_NORMALIZATION;
		double userUserNorm = 0.5;
		double userTrackNorm = 0.5;
		double trackUserNorm = 0.5;
		double trackTrackNorm = 0.5;
		
		parameters.setNormalizationMethod(normalizationMethod);
		parameters.setUserUserColumnNorm(userUserNorm);
		parameters.setTrackUserColumnNorm(trackUserNorm);
		parameters.setUserTrackColumnNorm(userTrackNorm);
		parameters.setTrackTrackColumnNorm(trackTrackNorm);
		
		int [] allUsers = parameters.getDatasetProperties().getUserList();
		int [] users = java.util.Arrays.copyOfRange(allUsers, 0, usersCount);
		
		parameters.setUsers(users);
		
		EvaluationMetric[] metrics = {
				new RecallPrecision(),
				new HalfLifeUtility(10)};
		
		parameters.setMetrics(metrics);
	}
	
	public static void setCosineUsersRecommendation(int usersCount) {
		ExperimentParameters parameters = ExperimentParameters.getInstance();
		
		parameters.setTitle("Cosine User-User Recommendation.");
		
		parameters.setDatasetType(ExperimentParameters.LASTFM_SMALL_DATASET);
		
		parameters.setIncludedRelations(ExperimentParameters.USERS_TRACKS_FRIENDS);
		
		parameters.setRestartProbability(0.8);
		
		int userMethod = ExperimentParameters.GET_COSINE_SIMILARITY;
		parameters.setUserUserValueRetrievalMethod(userMethod);
		
		int normalizationMethod = ExperimentParameters.SEPARATE_COLUMN_NORMALIZATION;
		double userNorm = 0.6;
		double trackNorm = 0.4;
		
		parameters.setNormalizationMethod(normalizationMethod);
		parameters.setUserUserColumnNorm(userNorm);
		parameters.setTrackUserColumnNorm(trackNorm);
		
		int [] allUsers = parameters.getDatasetProperties().getUserList();
		int [] users = java.util.Arrays.copyOfRange(allUsers, 0, usersCount);
		
		parameters.setUsers(users);
		
		EvaluationMetric[] metrics = {
				new RecallPrecision(),
				new HalfLifeUtility(10)};
		
		parameters.setMetrics(metrics);
	}
	
	public static void setFullUserTrackRecommendation(int usersCount) {
		ExperimentParameters parameters = ExperimentParameters.getInstance();
		
		parameters.setTitle("Cosine User-User Recommendation.");
		
		parameters.setDatasetType(ExperimentParameters.LASTFM_SMALL_DATASET);
		
		parameters.setIncludedRelations(ExperimentParameters.COMPLETE_USERS_TRACKS_GRAPH);
		
		parameters.setRestartProbability(0.8);
		
		int userMethod = ExperimentParameters.GET_COSINE_SIMILARITY;
		parameters.setUserUserValueRetrievalMethod(userMethod);
		
		int normalizationMethod = ExperimentParameters.SEPARATE_COLUMN_NORMALIZATION;
		double userUserNorm = 0.5;
		double userTrackNorm = 0.5;
		double trackUserNorm = 0.5;
		double trackTrackNorm = 0.5;
		
		parameters.setNormalizationMethod(normalizationMethod);
		parameters.setUserUserColumnNorm(userUserNorm);
		parameters.setTrackUserColumnNorm(trackUserNorm);
		parameters.setUserTrackColumnNorm(userTrackNorm);
		parameters.setTrackTrackColumnNorm(trackTrackNorm);
		
		int [] allUsers = parameters.getDatasetProperties().getUserList();
		int [] users = java.util.Arrays.copyOfRange(allUsers, 0, usersCount);
		
		parameters.setUsers(users);
		
		EvaluationMetric[] metrics = {
				new RecallPrecision(),
				new HalfLifeUtility(10)};
		
		parameters.setMetrics(metrics);
	}

	public static void setRestrictedRecommendation() {
		ExperimentParameters parameters = ExperimentParameters.getInstance();
		
		parameters.setTitle("Restricted User`s Graph Recommendation.");
		
		parameters.setDatasetType(ExperimentParameters.LASTFM_SMALL_DATASET);
		
		parameters.setIncludedRelations(ExperimentParameters.COMPLETE_USERS_TRACKS_GRAPH);
		
		parameters.setRestartProbability(0.8);
		
		int userMethod = ExperimentParameters.GET_COSINE_SIMILARITY;
		parameters.setUserUserValueRetrievalMethod(userMethod);
		
		int normalizationMethod = ExperimentParameters.SEPARATE_COLUMN_NORMALIZATION;
		double userUserNorm = 0.5;
		double userTrackNorm = 0.5;
		double trackUserNorm = 0.5;
		double trackTrackNorm = 0.5;
		
		parameters.setNormalizationMethod(normalizationMethod);
		parameters.setUserUserColumnNorm(userUserNorm);
		parameters.setTrackUserColumnNorm(trackUserNorm);
		parameters.setUserTrackColumnNorm(userTrackNorm);
		parameters.setTrackTrackColumnNorm(trackTrackNorm);
		
		EvaluationMetric[] metrics = {
				new HalfLifeUtility(10)};
		
		parameters.setMetrics(metrics);
	}
	
	/**
	 * @return  the userUserColumnNorm
	 */
	public double getUserUserColumnNorm() {
		return userUserColumnNorm;
	}

	/**
	 * @param userUserColumnNorm  the userUserColumnNorm to set
	 */
	public void setUserUserColumnNorm(double userUserColumnNorm) {
		this.userUserColumnNorm = userUserColumnNorm;
	}

	/**
	 * @return  the trackUserColumnNorm
	 */
	public double getTrackUserColumnNorm() {
		return trackUserColumnNorm;
	}

	/**
	 * @param trackUserColumnNorm  the trackUserColumnNorm to set
	 */
	public void setTrackUserColumnNorm(double trackUserColumnNorm) {
		this.trackUserColumnNorm = trackUserColumnNorm;
	}

	/**
	 * @return  the trackTrackColumnNorm
	 */
	public double getTrackTrackColumnNorm() {
		return trackTrackColumnNorm;
	}

	/**
	 * @param trackTrackColumnNorm  the trackTrackColumnNorm to set
	 */
	public void setTrackTrackColumnNorm(double trackTrackColumnNorm) {
		this.trackTrackColumnNorm = trackTrackColumnNorm;
	}

	/**
	 * @return  the userTrackColumnNorm
	 */
	public double getUserTrackColumnNorm() {
		return userTrackColumnNorm;
	}

	/**
	 * @param userTrackColumnNorm  the userTrackColumnNorm to set
	 */
	public void setUserTrackColumnNorm(double userTrackColumnNorm) {
		this.userTrackColumnNorm = userTrackColumnNorm;
	}

	/**
	 * @param relevantVerificationType  the relevantVerificationType to set
	 */
	public void setRelevantVerificationType(int relevantVerificationType) {
		this.relevantVerificationType = relevantVerificationType;
	}

	/**
	 * @return  the relevantVerificationType
	 */
	public int getRelevantVerificationType() {
		return relevantVerificationType;
	}
}
